home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step03 / scm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  15.5 KB  |  585 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  */
  25. /*
  26.  * SUP Communication Module for 4.3 BSD
  27.  *
  28.  * SUP COMMUNICATION MODULE SPECIFICATIONS:
  29.  *
  30.  * IN THIS MODULE:
  31.  *
  32.  * CONNECTION ROUTINES
  33.  *
  34.  *   FOR SERVER
  35.  *    servicesetup (port)    establish TCP port connection
  36.  *      char *port;            name of service
  37.  *    service ()        accept TCP port connection
  38.  *    servicekill ()        close TCP port in use by another process
  39.  *    serviceprep ()        close temp ports used to make connection
  40.  *    serviceend ()        close TCP port
  41.  *
  42.  *   FOR CLIENT
  43.  *    request (port,hostname,retry) establish TCP port connection
  44.  *      char *port,*hostname;          name of service and host
  45.  *      int retry;              true if retries should be used
  46.  *    requestend ()        close TCP port
  47.  *
  48.  * HOST NAME CHECKING
  49.  *    p = remotehost ()    remote host name (if known)
  50.  *      char *p;
  51.  *    i = samehost ()        whether remote host is also this host
  52.  *      int i;
  53.  *    i = matchhost (name)    whether remote host is same as name
  54.  *      int i;
  55.  *      char *name;
  56.  *
  57.  * RETURN CODES
  58.  *    All procedures return values as indicated above.  Other routines
  59.  *    normally return SCMOK on success, SCMERR on error.
  60.  *
  61.  * COMMUNICATION PROTOCOL
  62.  *
  63.  *    Described in scmio.c.
  64.  *
  65.  **********************************************************************
  66.  * HISTORY
  67.  *  2-Oct-92  Mary Thompson (mrt) at Carnegie-Mellon University
  68.  *    Added conditional declarations of INADDR_NONE and INADDR_LOOPBACK
  69.  *    since Tahoe version of <netinet/in.h> does not define them.
  70.  *
  71.  * $Log: scm.c,v $
  72.  * Revision 1.1.1.1  1993/05/21  14:52:17  cgd
  73.  * initial import of CMU's SUP to NetBSD
  74.  *
  75.  * Revision 1.13  92/08/11  12:05:35  mrt
  76.  *     Added changes from stump:
  77.  *       Allow for multiple interfaces, and for numeric addresses.
  78.  *       Changed to use builtin port for the "supfiledbg"
  79.  *         service when getservbyname() cannot find it.
  80.  *       Added forward static declatations, delinted.
  81.  *       Updated variable argument usage.
  82.  *     [92/08/08            mrt]
  83.  * 
  84.  * Revision 1.12  92/02/08  19:01:11  mja
  85.  *     Add (struct sockaddr *) casts for HC 2.1.
  86.  *     [92/02/08  18:59:09  mja]
  87.  * 
  88.  * Revision 1.11  89/08/03  19:49:03  mja
  89.  *     Updated to use v*printf() in place of _doprnt().
  90.  *     [89/04/19            mja]
  91.  * 
  92.  * 11-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  93.  *    Moved sleep into computeBackoff, renamed to dobackoff.
  94.  *
  95.  * 10-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  96.  *    Added timeout to backoff.
  97.  *
  98.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  99.  *    Removed nameserver support.
  100.  *
  101.  * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  102.  *    Fixed to depend less upon having name of remote host.
  103.  *
  104.  * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon Universtiy
  105.  *    Extracted backoff/sleeptime computation from "request" and
  106.  *    created "computeBackoff" so that I could use it in sup.c when
  107.  *    trying to get to nameservers as a group.
  108.  *
  109.  * 21-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
  110.  *    Merged divergent CS and EE versions.
  111.  *
  112.  * 02-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  113.  *    Added some bullet-proofing code around hostname calls.
  114.  *
  115.  * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
  116.  *    Fixed for 4.3.
  117.  *
  118.  * 30-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  119.  *    Added code to use known values for well-known ports if they are
  120.  *    not found in the host table.
  121.  *
  122.  * 19-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  123.  *    Changed setsockopt SO_REUSEADDR to be non-fatal.  Added fourth
  124.  *    parameter as described in 4.3 manual entry.
  125.  *
  126.  * 15-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  127.  *    Added call of readflush() to requestend() routine.
  128.  *
  129.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  130.  *    Major rewrite for protocol version 4.  All read/write and crypt
  131.  *    routines are now in scmio.c.
  132.  *
  133.  * 14-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  134.  *    Added setsockopt SO_REUSEADDR call.
  135.  *
  136.  * 01-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  137.  *    Removed code to "gracefully" handle unexpected messages.  This
  138.  *    seems reasonable since it didn't work anyway, and should be
  139.  *    handled at a higher level anyway by adhering to protocol version
  140.  *    number conventions.
  141.  *
  142.  * 26-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  143.  *    Fixed scm.c to free space for remote host name when connection
  144.  *    is closed.
  145.  *
  146.  * 07-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  147.  *    Fixed 4.2 retry code to reload sin values before retry.
  148.  *
  149.  * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  150.  *    Added code to retry initial connection open request.
  151.  *
  152.  * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  153.  *    Merged 4.1 and 4.2 versions together.
  154.  *
  155.  * 21-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  156.  *    Add close() calls after pipe() call.
  157.  *
  158.  * 12-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  159.  *    Converted for 4.2 sockets; added serviceprep() routine.
  160.  *
  161.  * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  162.  *    Created for 4.2 BSD.
  163.  *
  164.  **********************************************************************
  165.  */
  166.  
  167. #include <libc.h>
  168. #include <errno.h>
  169. #include <sys/param.h>
  170. #include <sys/types.h>
  171. #include <sys/time.h>
  172. #include <sys/socket.h>
  173. #include <sys/ioctl.h>
  174. #include <netinet/in.h>
  175. #include <arpa/inet.h>
  176. #include <net/if.h>
  177. #include <netdb.h>
  178. #if __STDC__
  179. #include <stdarg.h>
  180. #else
  181. #include <varargs.h>
  182. #endif
  183. #include "sup.h"
  184.  
  185. #if __STDC__
  186. int scmerr (int, char *, ...);
  187. #endif
  188.  
  189. #ifndef INADDR_NONE
  190. #define    INADDR_NONE        0xffffffff        /* -1 return */
  191. #endif
  192. #ifndef INADDR_LOOPBACK
  193. #define    INADDR_LOOPBACK        (u_long)0x7f000001    /* 127.0.0.1 */
  194. #endif
  195.  
  196. extern int errno;
  197. static char *myhost ();
  198.  
  199. char scmversion[] = "4.3 BSD";
  200.  
  201. /*************************
  202.  ***    M A C R O S    ***
  203.  *************************/
  204.  
  205. /* networking parameters */
  206. #define NCONNECTS 5
  207.  
  208. /*********************************************
  209.  ***    G L O B A L   V A R I A B L E S    ***
  210.  *********************************************/
  211.  
  212. extern char program[];            /* name of program we are running */
  213. extern int progpid;            /* process id to display */
  214.  
  215. int netfile = -1;            /* network file descriptor */
  216.  
  217. static int sock = -1;            /* socket used to make connection */
  218. static struct in_addr remoteaddr;    /* remote host address */
  219. static char *remotename = NULL;        /* remote host name */
  220. static int swapmode;            /* byte-swapping needed on server? */
  221.  
  222. /***************************************************
  223.  ***    C O N N E C T I O N   R O U T I N E S    ***
  224.  ***    F O R   S E R V E R                      ***
  225.  ***************************************************/
  226.  
  227. servicesetup (server)        /* listen for clients */
  228. char *server;
  229. {
  230.     struct sockaddr_in sin;
  231.     struct servent *sp;
  232.     short port;
  233.     int one = 1;
  234.  
  235.     if (myhost () == NULL)
  236.         return (scmerr (-1,"Local hostname not known"));
  237.     if ((sp = getservbyname(server,"tcp")) == 0) {
  238.         if (strcmp(server, FILEPORT) == 0)
  239.             port = htons((u_short)FILEPORTNUM);
  240.         else if (strcmp(server, DEBUGFPORT) == 0)
  241.             port = htons((u_short)DEBUGFPORTNUM);
  242.         else
  243.             return (scmerr (-1,"Can't find %s server description",server));
  244.         (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
  245.                     server,port);
  246.     } else
  247.         port = sp->s_port;
  248.     endservent ();
  249.     sock = socket (AF_INET,SOCK_STREAM,0);
  250.     if (sock < 0)
  251.         return (scmerr (errno,"Can't create socket for connections"));
  252.     if (setsockopt (sock,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0)
  253.         (void) scmerr (errno,"Can't set SO_REUSEADDR socket option");
  254.     (void) bzero ((char *)&sin,sizeof(sin));
  255.     sin.sin_family = AF_INET;
  256.     sin.sin_port = port;
  257.     if (bind (sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
  258.         return (scmerr (errno,"Can't bind socket for connections"));
  259.     if (listen (sock,NCONNECTS) < 0)
  260.         return (scmerr (errno,"Can't listen on socket"));
  261.     return (SCMOK);
  262. }
  263.  
  264. service ()
  265. {
  266.     struct sockaddr_in from;
  267.     int x,len;
  268.  
  269.     remotename = NULL;
  270.     len = sizeof (from);
  271.     do {
  272.         netfile = accept (sock,(struct sockaddr *)&from,&len);
  273.     } while (netfile < 0 && errno == EINTR);
  274.     if (netfile < 0)
  275.         return (scmerr (errno,"Can't accept connections"));
  276.     remoteaddr = from.sin_addr;
  277.     if (read(netfile,(char *)&x,sizeof(int)) != sizeof(int))
  278.         return (scmerr (errno,"Can't transmit data on connection"));
  279.     if (x == 0x01020304)
  280.         swapmode = 0;
  281.     else if (x == 0x04030201)
  282.         swapmode = 1;
  283.     else
  284.         return (scmerr (-1,"Unexpected byteswap mode %x",x));
  285.     return (SCMOK);
  286. }
  287.  
  288. serviceprep ()        /* kill temp socket in daemon */
  289. {
  290.     if (sock >= 0) {
  291.         (void) close (sock);
  292.         sock = -1;
  293.     }
  294.     return (SCMOK);
  295. }
  296.  
  297. servicekill ()        /* kill net file in daemon's parent */
  298. {
  299.     if (netfile >= 0) {
  300.         (void) close (netfile);
  301.         netfile = -1;
  302.     }
  303.     if (remotename) {
  304.         free (remotename);
  305.         remotename = NULL;
  306.     }
  307.     return (SCMOK);
  308. }
  309.  
  310. serviceend ()        /* kill net file after use in daemon */
  311. {
  312.     if (netfile >= 0) {
  313.         (void) close (netfile);
  314.         netfile = -1;
  315.     }
  316.     if (remotename) {
  317.         free (remotename);
  318.         remotename = NULL;
  319.     }
  320.     return (SCMOK);
  321. }
  322.  
  323. /***************************************************
  324.  ***    C O N N E C T I O N   R O U T I N E S    ***
  325.  ***    F O R   C L I E N T                      ***
  326.  ***************************************************/
  327.  
  328. dobackoff (t,b)
  329. int *t,*b;
  330. {
  331.     struct timeval tt;
  332.     unsigned s;
  333.  
  334.     if (*t == 0)
  335.         return (0);
  336.     s = *b * 30;
  337.     if (gettimeofday (&tt,(struct timezone *)NULL) >= 0)
  338.         s += (tt.tv_usec >> 8) % s;
  339.     if (*b < 32) *b <<= 1;
  340.     if (*t != -1) {
  341.         if (s > *t)
  342.             s = *t;
  343.         *t -= s;
  344.     }
  345.     (void) scmerr (-1,"Will retry in %d seconds",s);
  346.     sleep (s);
  347.     return (1);
  348. }
  349.  
  350. request (server,hostname,retry)        /* connect to server */
  351. char *server;
  352. char *hostname;
  353. int *retry;
  354. {
  355.     int x, backoff;
  356.     struct hostent *h;
  357.     struct servent *sp;
  358.     struct sockaddr_in sin, tin;
  359.     short port;
  360.  
  361.     if ((sp = getservbyname(server,"tcp")) == 0) {
  362.         if (strcmp(server, FILEPORT) == 0)
  363.             port = htons((u_short)FILEPORTNUM);
  364.         else if (strcmp(server, DEBUGFPORT) == 0)
  365.             port = htons((u_short)DEBUGFPORTNUM);
  366.         else
  367.             return (scmerr (-1,"Can't find %s server description",
  368.                     server));
  369.         (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
  370.                     server,port);
  371.     } else
  372.         port = sp->s_port;
  373.     (void) bzero ((char *)&sin,sizeof(sin));
  374.     sin.sin_family = AF_INET;
  375.     sin.sin_addr.s_addr = inet_addr (hostname);
  376.     if (sin.sin_addr.s_addr == (u_long) INADDR_NONE) {
  377.         if ((h = gethostbyname (hostname)) == NULL)
  378.             return (scmerr (-1,"Can't find host entry for %s",
  379.                     hostname));
  380.         hostname = h->h_name;
  381.         (void) bcopy (h->h_addr,(char *)&sin.sin_addr,h->h_length);
  382.     }
  383.     sin.sin_port = port;
  384.     backoff = 1;
  385.     for (;;) {
  386.         netfile = socket (AF_INET,SOCK_STREAM,0);
  387.         if (netfile < 0)
  388.             return (scmerr (errno,"Can't create socket"));
  389.         tin = sin;
  390.         if (connect(netfile,(struct sockaddr *)&tin,sizeof(tin)) >= 0)
  391.             break;
  392.         (void) scmerr (errno,"Can't connect to server for %s",server);
  393.         (void) close(netfile);
  394.         if (!dobackoff (retry,&backoff))
  395.             return (SCMERR);
  396.     }
  397.     remoteaddr = sin.sin_addr;
  398.     remotename = salloc(hostname);
  399.     x = 0x01020304;
  400.     (void) write (netfile,(char *)&x,sizeof(int));
  401.     swapmode = 0;        /* swap only on server, not client */
  402.     return (SCMOK);
  403. }
  404.  
  405. requestend ()            /* end connection to server */
  406. {
  407.     (void) readflush ();
  408.     if (netfile >= 0) {
  409.         (void) close (netfile);
  410.         netfile = -1;
  411.     }
  412.     if (remotename) {
  413.         free (remotename);
  414.         remotename = NULL;
  415.     }
  416.     return (SCMOK);
  417. }
  418.  
  419. /*************************************************
  420.  ***    H O S T   N A M E   C H E C K I N G    ***
  421.  *************************************************/
  422.  
  423. static
  424. char *myhost ()        /* find my host name */
  425. {
  426.     struct hostent *h;
  427.     static char name[MAXHOSTNAMELEN];
  428.  
  429.  
  430.     if (name[0] == '\0') {
  431.         if (gethostname (name,MAXHOSTNAMELEN) < 0)
  432.             return (NULL);
  433.         if ((h = gethostbyname (name)) == NULL)
  434.             return (NULL);
  435.         (void) strcpy (name,h->h_name);
  436.     }
  437.     return (name);
  438. }
  439.  
  440. char *remotehost ()    /* remote host name (if known) */
  441. {
  442.     register struct hostent *h;
  443.  
  444.     if (remotename == NULL) {
  445.         h = gethostbyaddr ((char *)&remoteaddr,sizeof(remoteaddr),
  446.                     AF_INET);
  447.         remotename = salloc (h ? h->h_name : inet_ntoa(remoteaddr));
  448.         if (remotename == NULL)
  449.             return("UNKNOWN");
  450.     }
  451.     return (remotename);
  452. }
  453.  
  454. int thishost (host)
  455. register char *host;
  456. {
  457.     register struct hostent *h;
  458.     char *name;
  459.  
  460.     if ((name = myhost ()) == NULL)
  461.         logquit (1,"Can't find my host entry");
  462.     h = gethostbyname (host);
  463.     if (h == NULL) return (0);
  464.     return (strcasecmp (name,h->h_name) == 0);
  465. }
  466.  
  467. int samehost ()        /* is remote host same as local host? */
  468. {
  469.     static struct in_addr *intp;
  470.     static int nint = 0;
  471.     struct in_addr *ifp;
  472.     int n;
  473.  
  474.     if (nint <= 0) {
  475.         int s;
  476.         char buf[BUFSIZ];
  477.         struct ifconf ifc;
  478.         struct ifreq *ifr;
  479.         struct sockaddr_in sin;
  480.  
  481.         if ((s = socket (AF_INET,SOCK_DGRAM,0)) < 0)
  482.             logquit (1,"Can't create socket for SIOCGIFCONF");
  483.         ifc.ifc_len = sizeof(buf);
  484.         ifc.ifc_buf = buf;
  485.         if (ioctl (s,SIOCGIFCONF,(char *)&ifc) < 0)
  486.             logquit (1,"SIOCGIFCONF failed");
  487.         (void) close(s);
  488.         if ((nint = ifc.ifc_len/sizeof(struct ifreq)) <= 0)
  489.             return (0);
  490.         intp = (struct in_addr *)
  491.             malloc ((unsigned) nint*sizeof(struct in_addr));
  492.         if ((ifp = intp) == 0)
  493.             logquit (1,"no space for interfaces");
  494.         for (ifr = ifc.ifc_req, n = nint; n > 0; --n, ifr++) {
  495.             (void) bcopy ((char *)&ifr->ifr_addr,(char *)&sin,sizeof(sin));
  496.             *ifp++ = sin.sin_addr;
  497.         }
  498.     }
  499.     if (remoteaddr.s_addr == htonl(INADDR_LOOPBACK))
  500.         return (1);
  501.     for (ifp = intp, n = nint; n > 0; --n, ifp++)
  502.         if (remoteaddr.s_addr == ifp->s_addr)
  503.             return (1);
  504.     return (0);
  505. }
  506.  
  507. int matchhost (name)    /* is this name of remote host? */
  508. char *name;
  509. {
  510.     struct hostent *h;
  511.     struct in_addr addr;
  512.     char **ap;
  513.     if ((addr.s_addr = inet_addr(name)) != (u_long) INADDR_NONE)
  514.         return (addr.s_addr == remoteaddr.s_addr);
  515.     if ((h = gethostbyname (name)) == 0)
  516.         return (0);
  517.     if (h->h_addrtype != AF_INET || h->h_length != sizeof(struct in_addr))
  518.         return (0);
  519.     for (ap = h->h_addr_list; *ap; ap++)
  520.         if (bcmp ((char *)&remoteaddr,*ap,h->h_length) == 0)
  521.             return (1);
  522.     return (0);
  523. }
  524.  
  525. #if __STDC__
  526. int scmerr (int errno,char *fmt,...)
  527. #else
  528. /*VARARGS*//*ARGSUSED*/
  529. int scmerr (va_alist)
  530. va_dcl
  531. #endif
  532. {
  533. #if !__STDC__
  534.     int errno;
  535.     char *fmt;
  536. #endif
  537.     va_list ap;
  538.  
  539.     (void) fflush (stdout);
  540.     if (progpid > 0)
  541.         fprintf (stderr,"%s %d: ",program,progpid);
  542.     else
  543.         fprintf (stderr,"%s: ",program);
  544. #if __STDC__
  545.     va_start(ap,fmt);
  546. #else
  547.     va_start(ap);
  548.     errno = va_arg(ap,int);
  549.     fmt = va_arg(ap,char *);
  550. #endif
  551.     vfprintf(stderr, fmt, ap);
  552.     va_end(ap);
  553.     if (errno >= 0)
  554.         fprintf (stderr,": %s\n",errmsg(errno));
  555.     else
  556.         fprintf (stderr,"\n");
  557.     (void) fflush (stderr);
  558.     return (SCMERR);
  559. }
  560.  
  561. /*******************************************************
  562.  ***    I N T E G E R   B Y T E - S W A P P I N G    ***
  563.  *******************************************************/
  564.  
  565. union intchar {
  566.     int ui;
  567.     char uc[sizeof(int)];
  568. };
  569.  
  570. int byteswap (in)
  571. int in;
  572. {
  573.     union intchar x,y;
  574.     register int ix,iy;
  575.  
  576.     if (swapmode == 0)  return (in);
  577.     x.ui = in;
  578.     iy = sizeof(int);
  579.     for (ix=0; ix<sizeof(int); ix++) {
  580.         --iy;
  581.         y.uc[iy] = x.uc[ix];
  582.     }
  583.     return (y.ui);
  584. }
  585.